import type { HostComponent, ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import {
  DirectEventHandler,
  Double,
  Int32,
  WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import type { UnsafeMixed } from './codegenUtils';

export type WebViewNativeEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
}>;
export type WebViewCustomMenuSelectionEvent = Readonly<{
  label: string;
  key: string;
  selectedText: string;
}>;
export type WebViewMessageEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
  data: string;
}>;
export type WebViewOpenWindowEvent = Readonly<{
  targetUrl: string;
}>;
export type WebViewHttpErrorEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
  description: string;
  statusCode: Int32;
}>;

export type WebViewErrorEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
  domain?: string;
  code: Int32;
  description: string;
}>;

export type WebViewNativeProgressEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
  progress: Double;
}>;

export type WebViewNavigationEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
  navigationType:
    | 'click'
    | 'formsubmit'
    | 'backforward'
    | 'reload'
    | 'formresubmit'
    | 'other';
  mainDocumentURL?: string;
}>;

export type ShouldStartLoadRequestEvent = Readonly<{
  url: string;
  loading: boolean;
  title: string;
  canGoBack: boolean;
  canGoForward: boolean;
  lockIdentifier: Double;
  navigationType:
    | 'click'
    | 'formsubmit'
    | 'backforward'
    | 'reload'
    | 'formresubmit'
    | 'other';
  mainDocumentURL?: string;
  isTopFrame: boolean;
}>;

type ScrollEvent = Readonly<{
  contentInset: {
    bottom: Double;
    left: Double;
    right: Double;
    top: Double;
  };
  contentOffset: {
    y: Double;
    x: Double;
  };
  contentSize: {
    height: Double;
    width: Double;
  };
  layoutMeasurement: {
    height: Double;
    width: Double;
  };
  targetContentOffset?: {
    y: Double;
    x: Double;
  };
  velocity?: {
    y: Double;
    x: Double;
  };
  zoomScale?: Double;
  responderIgnoreScroll?: boolean;
}>;

type WebViewRenderProcessGoneEvent = Readonly<{
  didCrash: boolean;
}>;

type WebViewDownloadEvent = Readonly<{
  downloadUrl: string;
}>;

// type MenuItem = Readonly<{label: string, key: string}>;

export interface NativeProps extends ViewProps {
  // Android only
  allowFileAccess?: boolean;
  allowsProtectedMedia?: boolean;
  allowsFullscreenVideo?: boolean;
  androidLayerType?: WithDefault<'none' | 'software' | 'hardware', 'none'>;
  cacheMode?: WithDefault<
    | 'LOAD_DEFAULT'
    | 'LOAD_CACHE_ELSE_NETWORK'
    | 'LOAD_NO_CACHE'
    | 'LOAD_CACHE_ONLY',
    'LOAD_DEFAULT'
  >;
  domStorageEnabled?: boolean;
  downloadingMessage?: string;
  forceDarkOn?: boolean;
  geolocationEnabled?: WithDefault<boolean, false>;
  lackPermissionToDownloadMessage?: string;
  messagingModuleName: string;
  minimumFontSize?: Int32;
  mixedContentMode?: WithDefault<'never' | 'always' | 'compatibility', 'never'>;
  nestedScrollEnabled?: boolean;
  onContentSizeChange?: DirectEventHandler<WebViewNativeEvent>;
  onRenderProcessGone?: DirectEventHandler<WebViewRenderProcessGoneEvent>;
  overScrollMode?: string;
  saveFormDataDisabled?: boolean;
  scalesPageToFit?: boolean;
  setBuiltInZoomControls?: boolean;
  setDisplayZoomControls?: boolean;
  setSupportMultipleWindows?: boolean;
  textZoom?: Int32;
  thirdPartyCookiesEnabled?: boolean;
  // Workaround to watch if listener if defined
  hasOnScroll?: boolean;
  // !Android only

  // iOS only
  allowingReadAccessToURL?: string;
  allowsBackForwardNavigationGestures?: boolean;
  allowsInlineMediaPlayback?: boolean;
  allowsAirPlayForMediaPlayback?: boolean;
  allowsLinkPreview?: boolean;
  automaticallyAdjustContentInsets?: boolean;
  ignoreSilentHardwareSwitch?:boolean;
  autoManageStatusBarEnabled?: boolean;
  bounces?: boolean;
  contentInset?: UnsafeMixed<Readonly<{
    top?: Double;
    left?: Double;
    bottom?: Double;
    right?: Double;
  }>>;
  contentInsetAdjustmentBehavior?: WithDefault<'never' | 'automatic' | 'scrollableAxes' | 'always', 'never'>;
  contentMode?: WithDefault<'recommended' | 'mobile' | 'desktop', 'recommended'>;
  dataDetectorTypes?: WithDefault<
    // eslint-disable-next-line @typescript-eslint/array-type
    UnsafeMixed<ReadonlyArray<'address' | 'link' | 'calendarEvent' | 'trackingNumber' | 'flightNumber' | 'lookupSuggestion' | 'phoneNumber' | 'all' | 'none'>>,
    'phoneNumber'
  >;
  decelerationRate?: Double;
  directionalLockEnabled?: boolean;
  enableApplePay?: boolean;
  hideKeyboardAccessoryView?: boolean;
  keyboardDisplayRequiresUserAction?: boolean;
  limitsNavigationsToAppBoundDomains?: boolean;
  mediaCapturePermissionGrantType?: WithDefault<
    | 'prompt'
    | 'grant'
    | 'deny'
    | 'grantIfSameHostElsePrompt'
    | 'grantIfSameHostElseDeny',
    'prompt'
  >;
  pagingEnabled?: boolean;
  pullToRefreshEnabled?: boolean;
  scrollEnabled?: boolean;
  sharedCookiesEnabled?: boolean;
  textInteractionEnabled?: boolean;
  useSharedProcessPool?: boolean;
  onContentProcessDidTerminate?: DirectEventHandler<WebViewNativeEvent>;
  onCustomMenuSelection?: DirectEventHandler<WebViewCustomMenuSelectionEvent>;
  onFileDownload?: DirectEventHandler<WebViewDownloadEvent>;
  // eslint-disable-next-line @typescript-eslint/array-type
  menuItems?: UnsafeMixed<ReadonlyArray<UnsafeMixed<Readonly<{label: string, key: string}>>>>;
  suppressMenuItems?: UnsafeMixed<Readonly<string>>[];
  // Workaround to watch if listener if defined
  hasOnFileDownload?: boolean;
  fraudulentWebsiteWarningEnabled?: boolean;
  
  // !iOS only

  allowFileAccessFromFileURLs?: boolean;
  allowUniversalAccessFromFileURLs?: boolean;
  applicationNameForUserAgent?: string;
  basicAuthCredential?: UnsafeMixed<Readonly<{
    username: string;
    password: string;
  }>>;
  cacheEnabled?: boolean;
  incognito?: boolean;
  injectedJavaScript?: string;
  injectedJavaScriptBeforeContentLoaded?: string;
  injectedJavaScriptForMainFrameOnly?: boolean;
  injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
  javaScriptCanOpenWindowsAutomatically?: boolean;
  javaScriptEnabled?: boolean;
  webviewDebuggingEnabled?: WithDefault<boolean, false>;
  mediaPlaybackRequiresUserAction?: boolean;
  messagingEnabled: boolean;
  shouldStartLoadWithRequestEnabled: boolean;
  onLoadingError: DirectEventHandler<WebViewErrorEvent>;
  onLoadingFinish: DirectEventHandler<WebViewNavigationEvent>;
  onLoadingProgress: DirectEventHandler<WebViewNativeProgressEvent>;
  onLoadingStart: DirectEventHandler<WebViewNavigationEvent>;
  onHttpError: DirectEventHandler<WebViewHttpErrorEvent>;
  onMessage: DirectEventHandler<WebViewMessageEvent>;
  onOpenWindow?: DirectEventHandler<WebViewOpenWindowEvent>;
  hasOnOpenWindowEvent?: boolean;
  onScroll?: DirectEventHandler<ScrollEvent>;
  onShouldStartLoadWithRequest: DirectEventHandler<ShouldStartLoadRequestEvent>;
  showsHorizontalScrollIndicator?: boolean;
  showsVerticalScrollIndicator?: boolean;
  newSource: UnsafeMixed<Readonly<{
    uri?: string
    method?: string;
    body?: string;
    // eslint-disable-next-line @typescript-eslint/array-type
    headers?: UnsafeMixed<ReadonlyArray<UnsafeMixed<Readonly<{name: string, value: string}>>>>;
    html?: string;
    baseUrl?: string;
  }>>;
  userAgent?: string;
  schemeList?: UnsafeMixed<ReadonlyArray<string>>;
}

export interface NativeCommands {
  goBack: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
  goForward: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
  reload: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
  stopLoading: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
  injectJavaScript: (
    viewRef: React.ElementRef<HostComponent<NativeProps>>,
    javascript: string
  ) => void;
  requestFocus: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
  postMessage: (
    viewRef: React.ElementRef<HostComponent<NativeProps>>,
    data: string
  ) => void;
  // Android Only
  loadUrl: (
    viewRef: React.ElementRef<HostComponent<NativeProps>>,
    url: string
  ) => void;
  clearFormData: (
    viewRef: React.ElementRef<HostComponent<NativeProps>>
  ) => void;
  clearCache: (
    viewRef: React.ElementRef<HostComponent<NativeProps>>,
    includeDiskFiles: boolean
  ) => void;
  clearHistory: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
  // !Android Only
}

export const Commands = codegenNativeCommands<NativeCommands>({
  supportedCommands: [
    'goBack',
    'goForward',
    'reload',
    'stopLoading',
    'injectJavaScript',
    'requestFocus',
    'postMessage',
    'loadUrl',
    'clearFormData',
    'clearCache',
    'clearHistory',
  ],
});

export default codegenNativeComponent<NativeProps>(
  'RNCWebView'
) as HostComponent<NativeProps>;
